

#include "tcp_ruitu.h"
#include "config.h"
#include <csignal>
#include <map>

#include "generater.h"

namespace TermSignal
{

   static bool keepRunning = false;

   void sig_handler(int sig){
   if ( sig == SIGINT)
   {
        keepRunning = false;
   }
}
void init()
{
    keepRunning = true;
    signal( SIGINT, sig_handler );
}

bool ok(){
    return keepRunning;
}

};

void client_for_result::loop()
{
    ready_for_connect();
    ready_for_socket();
    connect_to_server();
    //check_heartbeat_thread_ptr = new std::thread(
    //                                &client_for_result::check_heartbeat,this);
    generate_thread_for_heartbeat();
    generate_thread_for_alarm();
    //check_heartbeat_thread_ptr->join();
    check_heartbeat();
}

void client_for_result::generate_thread_for_alarm()
{
    send_alarm_thread_ptr = new std::thread(
                                &client_for_result::send_alarm,this);
    send_alarm_thread_ptr->detach();
}

void client_for_result::generate_thread_for_heartbeat()
{
    heartbeat_thread_ptr = new std::thread(
                               &client_for_result::heart_beat,this);
    heartbeat_thread_ptr->detach();
}


void client_for_result::feed_in(std::string & sending)
{
      lock_for_deque_ptr->lock();
      this->alarm_and_info.push_back(sending);
      lock_for_deque_ptr->unlock();
}


void client_for_result::outloop()
{
    lock_for_ctrl_ptr -> lock();
    ctrl_heart_beat = false;
    ctrl_alarm = false;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    ctrl_check_heart_beat = false;
    lock_for_ctrl_ptr -> unlock();
}




bool client_for_result::send_alarm()
{
    while(TermSignal::ok())
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        lock_for_ctrl_ptr -> lock();
        bool ctrl_alarm_copy = ctrl_alarm;
        bool ctrl_heart_beat_copy = ctrl_heart_beat;
        lock_for_ctrl_ptr -> unlock();
        if(ctrl_alarm_copy == false && ctrl_heart_beat_copy == false)
        {
            return false;
        }
        //lock_for_ctrl_ptr -> unlock();
        // if(ctrl_heart_beat == false)
        // {
        //      return false;
        // }
        //https://www.cnblogs.com/aiguona/p/7281739.html
        struct tcp_info info;
        int len=sizeof(info);
        getsockopt(client_sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
        if((info.tcpi_state==TCP_ESTABLISHED))
		{
			//std::cout<<"嵌套字可读 --- 发送报警线程"<<std::endl;
		}else{
			//std::cout<<"发送报警线程检测到嵌套字不可读 ---- 停止发送"<<std::endl;
            continue;
		} 
        if(alarm_and_info.empty())
        {
            continue;
        }
        else
        {
          
            lock_for_deque_ptr->lock();
            std::string alarm_info_temp = alarm_and_info[0];
            alarm_and_info.pop_front();
            lock_for_deque_ptr->unlock();
            lock_for_sending->lock();
            len=send(client_sockfd, alarm_info_temp.c_str(), 
                                  alarm_info_temp.size()+1, 0);
            std::cout<<alarm_info_temp.c_str()<<"  已经发送"<<std::endl;
            lock_for_sending->unlock();
        }
    }
    return true;
}

// /////////////////////////////////////////////////////////////////////sendalarm_new


void client_for_result::check_heartbeat()
{

    std::map<string, string> * config_for_overtime_ptr = new std::map<string, string>;
    overtime_ptr->ReadConfig(this_road_to_config+"config/config_overtime.cfg",
                        * config_for_overtime_ptr);
    int overtimenow = std::stoi((*config_for_overtime_ptr)["overtime"]);
    delete config_for_overtime_ptr;
    config_for_overtime_ptr = NULL;
    while(TermSignal::ok())
    {
        lock_for_ctrl_ptr -> lock();
        bool ctrl_check_heart_beat_copy = ctrl_check_heart_beat;
        lock_for_ctrl_ptr -> unlock();
        if(ctrl_check_heart_beat_copy == false)
        {
            break;
        }
        //lock_for_ctrl_ptr -> unlock();
        lock_for_heart_beat_ptr->lock();
        count_heartbeat+=1;
        //std::cout<<"未接受心跳包时间    "<<count_heartbeat<<std::endl;
        lock_for_heart_beat_ptr->unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        if(count_heartbeat>overtimenow)
        {
            std::cout<<"服务端掉线"<<std::endl;
            reconnect();
        }
    }
}


bool client_for_result::reconnect()
{
    label:
    try
    {
        if(!TermSignal::ok())
        {
           return true;
        }
        std::cout<<"尝试重新连接服务器"<<std::endl;
        while(!(alarm_and_info.empty()))
        {
            alarm_and_info.pop_back();
        }
        lock_for_ctrl_ptr -> lock();
        ctrl_heart_beat = false;
        ctrl_alarm = false;
        lock_for_ctrl_ptr -> unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        close(client_sockfd);
        int num_of_reconnect = 0;
        while(TermSignal::ok())
        {
            if(connet_max_number!=0 && num_of_reconnect>connet_max_number )
            {
                outloop();
                return false;
            }
            //std::cout<<num_of_reconnect<<std::endl;
            std::cout<<"尝试创建套接字"<<std::endl;
            int a , b;
            a = ready_for_socket();
            b = connect_to_server();
            std::this_thread::sleep_for(std::chrono::milliseconds(400));
            //std::cout<<"a%%%%%%%b"<<a<<b<<std::endl;
            if(a == true && b == true )
            {
                std::cout<<"连接服务器成功"<<std::endl;
                break;
            }else{
                num_of_reconnect++;
                close(client_sockfd);
            }
        }
        //ready_for_socket();
        // try{
        //connect_to_server();
        // }catch(...)
        // {
        //     std::cout<<"catch error "<<std::endl;
        //     goto label;
        // }
    }catch(...)
    {
        std::cout<<"捕获报错 "<<std::endl;
        goto label;
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
        delete heartbeat_thread_ptr;
        heartbeat_thread_ptr = NULL;
        delete send_alarm_thread_ptr;
        send_alarm_thread_ptr = NULL;
        lock_for_ctrl_ptr -> lock();
        ctrl_heart_beat = true;
        ctrl_alarm = true;
        lock_for_ctrl_ptr -> unlock();
        lock_for_heart_beat_ptr->lock();
        count_heartbeat = 0;
        lock_for_heart_beat_ptr->unlock();
        //std::cout<<"重新创建线程"<<std::endl;
        generate_thread_for_heartbeat();
        generate_thread_for_alarm();
        //std::cout<<"重新创建线程"<<std::endl;
        return true;
}


bool client_for_result::judgment()
{
     lock_for_judge_connect -> lock();
     bool now = judge_connect;
     lock_for_judge_connect -> unlock();
     return now;
}

bool client_for_result::heart_beat()
{
    struct tcp_info info_temp;
    int len_temp=sizeof(info_temp);
    getsockopt(client_sockfd, IPPROTO_TCP, TCP_INFO, &info_temp, (socklen_t *)&len_temp);
    if((info_temp.tcpi_state==TCP_ESTABLISHED))
    {
        std::cout<<"连接服务器成功"<<std::endl;
    }else{
        std::cout<<"连接服务器失败"<<std::endl;
    }
    //generate_helloack();
    generater_js->generate_helloack(helloACK,robotid);
    while(TermSignal::ok())
    {
        try
        {
            //std::cout<<"进入"<<"wwwwwwwww"<<ctrl_heart_beat<<std::endl;
            lock_for_ctrl_ptr -> lock();
            bool ctrl_heart_beat_copy = ctrl_heart_beat;
            lock_for_ctrl_ptr -> unlock();
            if(ctrl_heart_beat_copy == false)
             {
                 return false;
             }
             //lock_for_ctrl_ptr -> unlock();
            struct tcp_info info;
            int len=sizeof(info);
            getsockopt(client_sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
            if((info.tcpi_state==TCP_ESTABLISHED))
			{
                                lock_for_judge_connect -> lock();
				//std::cout<<"嵌套字可读 --- 心跳包线程"<<std::endl;
                                judge_connect = true;
                                lock_for_judge_connect -> unlock();
			}else{
				//std::cout<<"心跳包线程检测到嵌套字不可读 ---- 停止发送"<<std::endl;
                                lock_for_judge_connect -> lock();
                                judge_connect = false;
                                lock_for_judge_connect -> unlock();
                std::this_thread::sleep_for(std::chrono::milliseconds(300));
                continue;
			}
            lock_for_sending->lock(); 
            len=send(client_sockfd, helloACK.c_str(), helloACK.size()+1, 0);
            lock_for_sending->unlock();
            //std::cout<<"已经发送    >>>>   "<<helloACK.c_str()<<std::endl;
            //std::cout<<"长度       >>>>   "<<len<<std::endl;
            //recv_buf[len]='\0';
            len=recv(client_sockfd,recv_buf,BUFSIZ,0);
            helloACK_rec = recv_buf;
            //std::cout<<"已经接收    >>>>   "<<helloACK_rec<<std::endl;
            //std::cout<<"长度        >>>>   "<<len<<std::endl;
            if(TermSignal::ok())
            {
                std::this_thread::sleep_for(std::chrono::milliseconds(200));
                break;
            }
        }catch(...)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            reconnect();
        }
    }
    while(TermSignal::ok())
    {           
        try
        {
             lock_for_ctrl_ptr -> lock();
             bool ctrl_heart_beat_copy = ctrl_heart_beat;
             lock_for_ctrl_ptr -> unlock();
             if(ctrl_heart_beat_copy == false)
             {
                 return false;
             }
             //lock_for_ctrl_ptr -> unlock();
            struct tcp_info info;
            int len=sizeof(info);
            getsockopt(client_sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
            if((info.tcpi_state==TCP_ESTABLISHED))
			{
                                lock_for_judge_connect -> lock();
				judge_connect = true;//std::cout<<"嵌套字可读 --- 心跳包线程"<<std::endl;
                                lock_for_judge_connect -> unlock();
			}else{
                                lock_for_judge_connect -> lock();
				judge_connect = false;//std::cout<<"心跳包线程检测到嵌套字不可读 ---- 停止发送"<<std::endl;
                                lock_for_judge_connect -> unlock();
                std::this_thread::sleep_for(std::chrono::milliseconds(300));
                continue;
			} 
            //generate_heartbeat();
            generater_js->generate_heartbeat(this->heartbeat,robotid);
            lock_for_sending->lock();
            len=send(client_sockfd, heartbeat.c_str(), heartbeat.size()+1, 0);
            lock_for_sending->unlock();
            //std::cout<<"已经发送    >>>>   "<<heartbeat.c_str()<<std::endl;
            //std::cout<<"长度        >>>>   "<<len<<std::endl;
            //recv_buf[len]='\0';
            len=recv(client_sockfd,recv_buf,BUFSIZ,0);
            heartbeat_rec = recv_buf;
            //std::cout<<"已经接收    >>>>   "<<heartbeat_rec<<std::endl;
            //std::cout<<"长度        >>>>   "<<len<<std::endl;
            heartbeat_rec.erase(std::remove(heartbeat_rec.begin(), heartbeat_rec.end(), '*'), 
                                heartbeat_rec.end());
            heartbeat_rec.erase(std::remove(heartbeat_rec.begin(), heartbeat_rec.end(), '#'), 
                                heartbeat_rec.end());
            //std::cout<<"解析之后    -----   "<<heartbeat_rec<<std::endl;
            //std::cout<<"   -----   "<<count_heartbeat<<std::endl;
            if(len>0)
            {
                Json::Value judge;
                Json::Reader reader;
                if(reader.parse(heartbeat_rec, judge))
                {
                //std::cout<<judge.isMember("heartbeat")<<std::endl; 
                    if(judge.isMember("Heartbeat"))
                    {
                         lock_for_heart_beat_ptr->lock();
                         count_heartbeat = 0;
                         lock_for_heart_beat_ptr->unlock();
                    }
                } 
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(400));
        }catch(...)
        {
            std::cout<<"catched"<<std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            reconnect();
        }
    }
    return true;
}


bool client_for_result::ready_for_connect()
{
    std::map<string, string> * config_for_ip_ptr = new std::map<string, string>;
    ip_ptr->ReadConfig(this_road_to_config+"config/config_ip.cfg",
                        * config_for_ip_ptr);
    const char *p = (*config_for_ip_ptr)["ip"].data();
    int n = std::stoi((*config_for_ip_ptr)["port"]);
    remote_addr.sin_family=AF_INET;//设置为IP通信
	remote_addr.sin_addr.s_addr=inet_addr(p);//服务器IP地址
	remote_addr.sin_port=htons(n);//服务器端口号
    delete config_for_ip_ptr;
    config_for_ip_ptr = NULL;
    return true;
}

bool client_for_result::ready_for_socket()
{
    if((client_sockfd=socket(PF_INET, SOCK_STREAM, 0))<0)
	{
        //close(client_sockfd);
		//std::cout<<"socket 报错"<<std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(600));
        //ready_for_socket();
		return false;//
	}
    return true;
}


bool client_for_result::connect_to_server()
{
    if(connect(client_sockfd, (struct sockaddr*)&remote_addr, sizeof(struct sockaddr))<0)
	{
        //close(client_sockfd);
		//std::cout<<"connect 报错"<<std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(600));
        //connect_to_server();
		return false;
	}
    return true; 
}


client_for_result::client_for_result(const std::string &road_to_config,int connet_max, std::string id)
{
    memset(&remote_addr, 0, sizeof(remote_addr));
    connet_max_number = connet_max;
    this_road_to_config = road_to_config;
    ctrl_heart_beat = true;
    ctrl_alarm = true;
    ctrl_check_heart_beat = true;
    judge_connect = false;
    robotid = id;
    
    TermSignal::init(); 
}

client_for_result::~client_for_result()
{
    close(client_sockfd);
    outloop();
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    //elete come_with_server_ptr;
    delete check_heartbeat_thread_ptr;
    delete lock_for_heart_beat_ptr;
    delete send_alarm_thread_ptr;
    delete heartbeat_thread_ptr;
    delete ip_ptr;
    delete generater_js;
    delete overtime_ptr;
    //delete test_picture_str_ptr;
    delete lock_for_sending;
    delete lock_for_ctrl_ptr;
    delete lock_for_judge_connect;
    //come_with_server_ptr = NULL;
    check_heartbeat_thread_ptr = NULL;
    lock_for_heart_beat_ptr = NULL;
    send_alarm_thread_ptr = NULL;
    heartbeat_thread_ptr = NULL;
    ip_ptr = NULL;
    generater_js = NULL;
    overtime_ptr = NULL;
    //test_picture_str_ptr = NULL;
    lock_for_sending = NULL;
    lock_for_judge_connect = NULL;
    std::cout<<"上位机连接类---析构函数已经调用"<<std::endl;
}


//1 peizhiwenjian
//2 leifengzhuang
//3 try catch
//4https://blog.csdn.net/zhizhengguan/article/details/107252204
//https://blog.csdn.net/qingtian11112/article/details/109880685

//https://blog.csdn.net/weixin_44024891/article/details/105125177
//https://blog.csdn.net/weixin_42073412/article/details/102607439 TCP之多线程

//picture

    // Json::Value root;
    // Json::Reader reader;
    // //reader负责从字符串中解析出json格式数据
    // if(reader.parse(file_content, root))
    // {
    //     std::string name = root["name"].asString();
    //     std::cout << "name: " << name << std::endl;
    //     std::string sex = root["sex"].asString();
    //     std::cout << "sex: " << sex << std::endl;
    //     int age = root["age"].asInt();
    //     std::cout << "age: " << age << std::endl;

    //     Json::Value node = root["教育经历"];
    //     std::string education = node["学历"].asString();
    //     std::cout << "education: " << education << std::endl;
    //     std::string university = node["学校"].asString();
    //     std::cout << "university: " << university << std::endl;
    //     std::string major = node["专业"].asString();
    //     std::cout << "major: " << major << std::endl;
    // }
